/********************************************************************/
/*  Copyright (C) School of Software Engineering of USTC, 2012                               
/*                                                                                                                       
/*  FILE NAME: dbapi.c                                                                                          
/*  PRINCIPAL AUTHOR: SA12226114(Xin Zhu), SA12226139(Dan Shu)                    
/*  SUBSYSTEM NAME: DB                                                                                    
/*  MODULE NAME: dbserver.c                                                                                      
/*  LANGUAGE: C                                                                                                 
/*  TARGET ENVIRONMENT: Linux                                                                          
/*  DATE OF FIRST RELEASE: 2012-12-10                                                             
/*  DESCRIPTION: Impement of Abstract Interface for Tokyo Cabinet DB API              
/********************************************************************/


#include "router.h"


#define MAX_TASK_NUM 10
void dispatch(void *);


pthread_t thread_id[MAX_TASK_NUM];
void *g_db = NULL;

struct node_s g_memcache_nodes[100] = {0};
struct conhash_s *g_conhash;

typedef struct fd
{
    int listenfd;
    int connfd;
}fd_t;

int g_index = 0;


/*****************************************************************
Function Name: main
Description:
Parameter:  

@argc: argument count
@argv: argument vector

Author: 
Date:  
comment:

epoll advantages:
0. cost less than apache web server(Process for per connection and Thread for per connection)
1. no limit of connections
2. epoll's efficient is more than select and poll.
3. application and kernel share memory space, reduce the cost of memory copy. 

reference links:
epoll
1. http://blog.csdn.net/sparkliang/article/details/4770655
2. https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/
3. http://www.cnblogs.com/bourneli/archive/2011/12/30/unp.html
---------------------------------------------------------------------
epoll structure:

typedef union epoll_data
{
  void        ptr;
  int          fd;
  __uint32_t   u32;
  __uint64_t   u64;
} epoll_data_t;

struct epoll_event
{
  __uint32_t   events;  // Epoll events 
  epoll_data_t data;    // User data variable 
};

consistent hash
http://blog.csdn.net/sparkliang/article/details/5279393
http://blog.csdn.net/bintime/article/details/6259133


******************************************************************/
int main(int argc, char** argv)
{
    int listenfd, connfd, epfd, nfds, index, status;
    struct sockaddr_in servaddr;
    struct sockaddr_in client_addr;
    void *db = NULL;
    char cmdline[CMDLINE_LEN], cmd[CMD_LEN], key[KEY_LEN], value[VALUE_LEN], retval[VALUE_LEN] = {0};
    struct epoll_event ev, events[20];

    /* init conhash instance */
    g_conhash = conhash_init(NULL);
    if(!g_conhash)
    {
        printf("conhash is null\n");

        return 0;
    }

    /* initialize thread pool, we need to destroy thread pool when we exit program. */
    pool_init(10);

    /* generate a new socket for server end */
    listenfd = sw_create_socket(PF_INET, SOCK_STREAM, 0);

    /* initialize structure sockaddr_in with protocol family, ip, port number */
    sw_init_socket2(&servaddr, sizeof(servaddr));

    /* bind socket and socket id */
    sw_bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

    /* the second parameter is max number of client connection */
    sw_listen(listenfd, 10);

    
    /* generate a specific epoll file descriptor for accepting */
    epfd = epoll_create(256);

    /* make the socket non blocking */
    sw_make_socket_non_blocking(listenfd);
    
    ev.data.fd = listenfd;                   /* file descriptor needs to be watched */
    ev.events = EPOLLIN|EPOLLHUP|EPOLLOUT|EPOLLET;   /* event type needs to be handled */

    /* register epoll event */
    epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
    
    /* The event loop */
    while(1)
    {
        struct sockaddr in_addr;
        socklen_t in_len;
        char hbuf[200], sbuf[200];
        in_len = sizeof(in_addr);
        fd_t fd;
        
        /* epoll_wait blocks until events are available */
        nfds = epoll_wait(epfd, events, 500, 500);

        /* handle event */
        for(index = 0; index < nfds; ++index)
        {
            /* We have a notification on the listening socket, which means one or more new incoming connections. */
            if(events[index].data.fd == listenfd)
            {                
                /* accept new connection from client */
                //connfd = sw_accept(listenfd);
                if((connfd = accept(listenfd, &in_addr, &in_len)) == -1)
                {
                    printf("accept socket error: %s(errno: %d)", strerror(errno), errno);

                    return 0;
                }

                /* get connection info */
                status = getnameinfo(&in_addr, in_len, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
                if(status == 0)
                    debug_print("Accepted connection on descriptor %d (host=%s, port=%s)\n", connfd, hbuf, sbuf);

                //fd.listenfd = listenfd;
                //fd.connfd = connfd;
                pool_add_job(dispatch, &listenfd);
            
                /* make the incoming socket non-blocking and add it to the list of fds to monitor. */
                sw_make_socket_non_blocking(connfd);

                ev.data.fd = connfd;
                ev.events = EPOLLIN|EPOLLET;
                
                epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
            }
            else if(events[index].events & EPOLLIN) /* It is existed connection and there are data incoming. */
            {
                //fd.listenfd = listenfd;
                //fd.connfd = events[index].data.fd;
                pool_add_job(dispatch, &events[index].data.fd);
            }
            
        }
    }


}


/*****************************************************************
Function Name: 
Description:  
Parameter:  
Author: SA12226114(Xin Zhu), SA12226139(Dan Shu)
Date: 2012-12-20
******************************************************************/
void dispatch(void *sockfd)
{
    int listenfd, connfd, epfd, nfds, i = 0;
    struct sockaddr_in servaddr;
    struct sockaddr_in client_addr;
    char cmdline[CMDLINE_LEN] = {0}, action[CMD_LEN], parameter[KEY_LEN], value[VALUE_LEN];
    struct node_s* memcache_node_s;

    util_init(cmdline, CMDLINE_LEN);
    while((sw_recv((*(int *)sockfd), cmdline, CMDLINE_LEN, 0)) > 0)
    {
        util_init(action, CMD_LEN);
        util_init(parameter, KEY_LEN);
        util_parse(cmdline, CMDLINE_LEN, action, parameter, NULL);
        util_memset(action, CMD_LEN);
        util_memset(parameter, KEY_LEN);

        printf("cmdline=%s, action=%s, parameter=%s\n",cmdline, action, parameter);
        
        if(strncmp(action, "add_memcache_node", sizeof("add_memcache_node")) == 0)
        {
            printf("enter add_memcache_node\n");
            conhash_set_node(&g_memcache_nodes[g_index], parameter, parameter, 32);
            conhash_add_node(g_conhash, &g_memcache_nodes[g_index]);
            g_index++;
        }
        else if(strncmp(action, "set", sizeof("set")) == 0 || 
                strncmp(action, "get", sizeof("get")) == 0)
        {
            printf("parameter=%s", parameter);
            memcache_node_s = conhash_lookup(g_conhash, parameter);
            if(memcache_node_s)
                printf("[%16s] is in node: [%16s] ip=%s\n", parameter, memcache_node_s->iden, memcache_node_s->ip);

            /* send this ip(memcache_node_s->ip) to client */
            sw_send((*(int *)sockfd), memcache_node_s->ip, 32, 0);
        }
        else if(strncmp(action, "open", sizeof("open")) == 0)
        {
            /* send this ip(memcache_node_s->ip) to client */
            //sw_send((*(int *)sockfd), memcache_node_s->ip, 32, 0);
        
        }
        else
        {
            printf("else\n");
        }

        util_init(cmdline, CMDLINE_LEN);
    }

    /* memcache crash down */
    if((sw_recv((*(int *)sockfd), cmdline, CMDLINE_LEN, 0)) == 0)
    {
        
        for(; i < 100; i++)
        {
            printf("enter remove_memcache_node, g_memcache_nodes[%d].ip=%s, ip=%s\n", i, g_memcache_nodes[i].ip, parameter);

            
            if(strncmp(g_memcache_nodes[i].ip, parameter, 32) == 0)
            {
                conhash_del_node(g_conhash, &g_memcache_nodes[i]);
                printf("enter remove_memcache_node, ip=%s\n", parameter);

                break;
            }
            

            if(strlen(g_memcache_nodes[i].ip) > 0)
            {
                struct sockaddr_in servaddr;
                int socketfd;

                /* generate a new socket for client */
                socketfd = sw_create_socket(PF_INET, SOCK_STREAM, 0);
                
                /* initialize structure sockaddr_in with protocol family, port number, ip */
                sw_init_socket(&servaddr, sizeof(servaddr), g_memcache_nodes[i].ip);
                
                /* connect server using socket id */
                if(!sw_connect(socketfd, (struct sockaddr*)&servaddr, sizeof(servaddr)))
                {
                    //debug_print("sw_connect_server can not connet to server.\n");
                    //printf("g_memcache_nodes[%d].ip=%s, ip=%s\n", i, g_memcache_nodes[i].ip);
                    conhash_del_node(g_conhash, &g_memcache_nodes[i]);
                    memset(&g_memcache_nodes[i], 0, sizeof(struct node_s));

                }
            }
            
            
        }
    }

    return;
}


/*****************************************************************
Function Name: 
Description:  
Parameter:  
Author: SA12226114(Xin Zhu), SA12226139(Dan Shu)
Date: 2012-12-20
******************************************************************/
void *insert_memcache_node(void *arg)
{





}


/*****************************************************************
Function Name: 
Description:  
Parameter:  
Author: SA12226114(Xin Zhu), SA12226139(Dan Shu)
Date: 2012-12-20
******************************************************************/
void *delete_memcache_node(void *arg)
{




}







